package com.atwisdom.star.service.business;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.util.JsonUtil;
import com.atwisdom.star.common.util.SpringContextUtil;
import com.atwisdom.star.common.util.UuidTool;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.workCenter.WorkCenterInstance;
import com.atwisdom.star.core.dsl.modelClass.logic.Impl.LogicInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.twins.Impl.TwinsInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.workCenter.Impl.WorkCenterInstanceDslServiceImpl;
import com.atwisdom.star.exception.pojo.BusinessException;
import com.atwisdom.star.service.pojo.BasicStatus;
import com.atwisdom.star.service.status.WorkCenterStatus;
import com.atwisdom.star.service.status.WorkNoticeStatus;
import com.atwisdom.star.service.util.ArithUtil;
import lombok.Data;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName: WorkCenter
 * @ Description: 工作中心定制化处理操作
 * @author: 王红艳
 * @date:2024/05/15 10:30
 */
@Service
@Data
public class WorkCenter extends Business{
    private final WorkCenterInstanceDslServiceImpl workCenterService  = SpringContextUtil.getBean(WorkCenterInstanceDslServiceImpl.class);
    private final LogicInstanceDslServiceImpl childInstanceService = SpringContextUtil.getBean(LogicInstanceDslServiceImpl.class);
    private final TwinsInstanceDslServiceImpl workUintService = SpringContextUtil.getBean(TwinsInstanceDslServiceImpl.class);

    private WorkCenterInstance workCenter;
    private List<JSONObject> BOM;
    private List<JSONObject> inputRecords;
    private JSONObject inputSummary;
    private JSONObject inputSummaryRest;
    private JSONObject inputException;
    private JSONObject workNotice;
    private List<JSONObject> outputRecords;
    private JSONObject outputSummary;
    private JSONObject outputSummaryRest;
    private JSONObject outputException;
    private WorkUnit workUnit;
    private JSONObject statistics;

    private final String BOMName = "BOM";
    private final String inputRecordsName = "InputRecords";
    private final String inputSummaryName = "InputSummary";
    private final String inputSummaryRestName = "InputSummaryRest";
    private final String inputExceptionName = "InputException";
    private final String workNoticeName = "WorkNotice";
    private final String outputRecordsName = "OutputRecords";
    private final String outputSummaryName = "OutputSummary";
    private final String outputSummaryRestName = "OutputSummaryRest";
    private final String outputExceptionName = "OutputException";
    private final String workUnitName = "WorkUnit";
    private final String statisticsName = "Statistics";

    private final String workCenterModel = "workCenter";
    private final String workCenterType = "workCenter";
    private final String workNoticeClassName = "WorkNotice";
    private final String workNoticeType = "logic";

    /**
     * 更新工作中心状态
     * @param id 实例id
     * @param status 状态
     */
    public void updateWorkCenterStatus(Long id,String status){
        WorkCenterStatus workCenterStatus = new WorkCenterStatus(id);
        workCenterStatus.setUpdateStatus(workCenterStatus.getStatusKey(),status);
        workCenterStatus.next();
    }

    /**
     * 回退工作中心状态
     * @param id 实例id
     * @param status 状态
     */
    public void updateWorkCenterStatusBack(Long id,String status){
        WorkCenterStatus workCenterStatus = new WorkCenterStatus(id);
        workCenterStatus.setUpdateStatus(workCenterStatus.getStatusKey(),status);
        workCenterStatus.back();
    }

    /**
     * 更新工单状态
     * @param id 实例id
     * @param status 状态
     */
    public void updateWorkNoticeStatus(Long id,String status){
        WorkNoticeStatus workNoticeStatus = new WorkNoticeStatus(id);
        workNoticeStatus.setUpdateStatus(workNoticeStatus.getStatusKey(),status);
        workNoticeStatus.next();
    }

    /**
     * 回退工单状态
     * @param id 实例id
     * @param status 状态
     */
    public void updateWorkNoticeStatusBack(Long id,String status){
        WorkNoticeStatus workNoticeStatus = new WorkNoticeStatus(id);
        workNoticeStatus.setUpdateStatus(workNoticeStatus.getStatusKey(),status);
        workNoticeStatus.back();
    }
    /**
     * 根据名称获取父级id
     * @param name 父级名称
     * @return
     */
    private String getParentIdByName(String name){
        List<HierInstance> hierList = workCenter.getHierInstances().stream().filter(hierInstance -> name.equals(hierInstance.getName())).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(hierList)){
            throw new BusinessException("父级"+name+"不存在");
        }
        return hierList.get(0).getNodeId();
    }

    /**
     * 获取子级实例
     * @param parentId 父级id
     * @return
     */
    private List<JSONObject> getHierInstancesLinkJson(String parentId) {
        return workCenter.getHierInstances().stream()
                .filter(hierInstance -> parentId.equals(hierInstance.getParentId())&&null!=hierInstance.getLinkId())
                .map(hierInstance -> childInstanceService.queryJsonById(hierInstance.getLinkId()))
                .collect(Collectors.toList());
    }

    /**
     * 获取子级实例
     * @param parentId 父级id
     * @return
     */
    private JSONObject getHierInstanceLinkJson(String parentId) {
         List<JSONObject> hierList= workCenter.getHierInstances().stream()
                .filter(hierInstance -> parentId.equals(hierInstance.getParentId())&&null!=hierInstance.getLinkId())
                .map(hierInstance -> childInstanceService.queryJsonById(hierInstance.getLinkId()))
                .collect(Collectors.toList());
         return CollectionUtil.isEmpty(hierList)?null:hierList.get(0);
    }

    /**
     * 获取子级json
     * @param parentId 父级id
     * @return
     */
    private JSONObject getHierInstanceJson(String parentId) {
        List<JSONObject> hierList= workCenter.getHierInstances().stream()
                .filter(hierInstance -> parentId.equals(hierInstance.getParentId()))
                .map(hierInstance -> hierInstanceDslServiceImpl.convertToJson(hierInstance))
                .collect(Collectors.toList());
        return CollectionUtil.isEmpty(hierList)?null:hierList.get(0);
    }

    /**
     * 获取子级json
     * @param parentId 父级id
     * @return
     */
    private List<JSONObject> getHierInstanceJsonList(String parentId) {
        List<JSONObject> hierList= workCenter.getHierInstances().stream()
                .filter(hierInstance -> parentId.equals(hierInstance.getParentId()))
                .map(hierInstance -> hierInstanceDslServiceImpl.convertToJson(hierInstance))
                .collect(Collectors.toList());
        return hierList;
    }



    /**
     * 获取工位实例
     * @param nodeId 工位nodeId
     * @return
     */
    private WorkUnit getTwins(String nodeId) {
        List<WorkUnit> hierList= workCenter.getHierInstances().stream()
                .filter(hierInstance -> nodeId.equals(hierInstance.getNodeId())&&null!=hierInstance.getLinkId())
                .map(hierInstance -> {
                    WorkUnit workUnit = new WorkUnit();
                    workUnit.setWorkUnit(hierInstance.getLinkId());
                    return workUnit;
                })
                .collect(Collectors.toList());
        if(CollectionUtil.isEmpty(hierList)){
            throw new BusinessException("工位不存在");
        }
        return hierList.get(0);
    }

    /**
     * 初始化工作中心
     * @param id 工作中心id`
     */
    public void setWorkCenter(Long id){
        setWorkCenter(workCenterService.queryById(id));
    }

    /**
     * 初始化工作中心
     * @param workCenter 工作中心实例
     */
    public void setWorkCenter(WorkCenterInstance workCenter) {
        if(null==workCenter){
            throw new BusinessException("工作中心不存在");
        }
        this.workCenter = workCenter;
        this.BOM = getHierInstanceJsonList(getParentIdByName(BOMName));
        this.inputRecords = getHierInstancesLinkJson(getParentIdByName(inputRecordsName));
        this.inputSummary = getHierInstanceJson(getParentIdByName(inputSummaryName));
        this.inputSummaryRest = getHierInstanceJson(getParentIdByName(inputSummaryRestName));
        this.inputException = getHierInstanceJson(getParentIdByName(inputExceptionName));
        this.workNotice = getHierInstanceLinkJson(getParentIdByName(workNoticeName));
        this.outputRecords = getHierInstancesLinkJson(getParentIdByName(outputRecordsName));
        this.outputSummary = getHierInstanceJson(getParentIdByName(outputSummaryName));
        this.outputSummaryRest = getHierInstanceJson(getParentIdByName(outputSummaryRestName));
        this.outputException = getHierInstanceJson(getParentIdByName(outputExceptionName));
        this.workUnit = getTwins(getParentIdByName(workUnitName));
        this.statistics = getHierInstanceLinkJson(getParentIdByName(statisticsName));
    }

    /**
     * 添加输入记录
     * @param inputRecord 输入记录
     */
    public void addInputRecord(JSONObject inputRecord){
        addChild(this.workCenterModel,this.workCenter.getClassName(),this.workCenter.getId(),getParentIdByName(inputRecordsName),JsonUtil.buildJson(new Object[]{"linkId",inputRecord.getLong("id"),"linkClassName",inputRecord.getString("className"),"hierValues",inputRecord.getJSONObject("values")}));
        this.inputRecords.add(inputRecord);
        inputSummary();
        inputSummaryRest();
        inputException();
        statistics();
    }

    /**
     * 输入汇总统计
     * @return
     */
    public void inputSummary(){
        BigDecimal summary = new BigDecimal(0);
        for(int i=0;i<this.inputRecords.size();i++){
            JSONObject inputRecord = this.inputRecords.get(i);
            BigDecimal weight = new BigDecimal(null==JsonUtil.get(inputRecord,"values.weight")?"0":JsonUtil.get(inputRecord,"values.weight").toString());
            if(Boolean.valueOf(JsonUtil.get(inputRecord,"values.pickStatus").toString())){
                summary = ArithUtil.bigDecimalAddToBigDecimal(summary,weight);
            }else{
                summary = ArithUtil.bigDecimalSubToBigDecimal(summary,weight);
            }
        }
        JSONObject dataJson = JsonUtil.buildJson(new Object[]{"id",null==this.inputSummary?null:this.inputSummary.getLong("id"),"hierValues",JsonUtil.buildJson(new Object[]{"summary",summary})});
        List<HierInstance> hierList = hierInstanceDslServiceImpl.addChild(this.workCenterModel,this.workCenter.getClassName(),this.workCenter.getId(),getParentIdByName(inputSummaryName),Arrays.asList(dataJson));
        if(CollectionUtil.isEmpty(hierList)){
            throw new BusinessException("输入汇总不存在");
        }
        this.inputSummary = this.hierInstanceDslServiceImpl.convertToJson(hierList.get(0));
    }

    /**
     * 输入剩余汇总统计
     * @return
     */
    public JSONObject inputSummaryRest(){
        return this.inputSummaryRest;
    }

    /**
     * 输入异常统计
     * @return
     */
    public JSONObject inputException(){
        return this.inputException;
    }

    /**
     * 添加输出记录
     * @param outputRecord 数据记录
     */
    public void addOutputRecord(JSONObject outputRecord){
        addChild(this.workCenterModel,this.workCenter.getClassName(),this.workCenter.getId(),getParentIdByName(outputRecordsName),JsonUtil.buildJson(new Object[]{"linkId",outputRecord.getLong("id"),"linkClassName",outputRecord.getString("className"),"hierValues",outputRecord.getJSONObject("values")}));
        this.outputRecords.add(outputRecord);
        /*outputSummary();*/
        outputSummaryRest();
        outputException();
        statistics();
    }

    /**
     * 输出汇总统计
     * @return
     */
    public void outputSummary(){
        BigDecimal summary = new BigDecimal(0);
        for(int i=0;i<this.outputRecords.size();i++){
            JSONObject outputRecord = this.outputRecords.get(i);
            BigDecimal weight = new BigDecimal(null==JsonUtil.get(outputRecord,"values.weight")?"0":JsonUtil.get(outputRecord,"values.weight").toString());
            summary = ArithUtil.bigDecimalAddToBigDecimal(summary,weight);
        }
        JSONObject dataJson = JsonUtil.buildJson(new Object[]{"id",null==this.outputSummary?null:this.outputSummary.getLong("id"),"hierValues",JsonUtil.buildJson(new Object[]{"summary",summary})});
        List<HierInstance> hierList = hierInstanceDslServiceImpl.addChild(this.workCenterModel,this.workCenter.getClassName(),this.workCenter.getId(),getParentIdByName(outputSummaryName),Arrays.asList(dataJson));
        if(CollectionUtil.isEmpty(hierList)){
            throw new BusinessException("输出汇总不存在");
        }
        this.outputSummary = this.hierInstanceDslServiceImpl.convertToJson(hierList.get(0));
    }

    /**
     * 输出剩余汇总统计
     * @return
     */
    public JSONObject outputSummaryRest(){
        return this.outputSummaryRest;
    }

    /**
     * 输出异常统计
     * @return
     */
    public JSONObject outputException(){
        return this.outputException;
    }

    /**
     * 统计
     * @return
     */
    public JSONObject statistics(){
        return this.statistics;
    }

    /**
     * 初始化工作中心
     * @param className 工作中心类名
     * @param values 工作中心初始化数据
     */
    public void initWorkCenter(String className, JSONObject values){
        WorkCenterInstance workCenterInstance = workCenterUtil.add(workCenterType,className, UuidTool.getUUID32(),values);
        setWorkCenter(workCenterInstance);
    }

    /**
     * 下派
     * @param values 下派值
     */
    public void execute(JSONObject values){
        values.remove("status");
        workCenterService.updateById(getExecuteJson(this.workCenter.getId(),this.workCenter.getClassName(),workCenterType,values));
        updateWorkCenterStatus(this.workCenter.getId(), BasicStatus.WORK_CENTER_STATUS_EXECUTE);
        JSONObject workNoticeJson = childInstanceService.add(getNoticeJson(this.workNoticeClassName,this.workNoticeType,values));
        workUnit.addWorkNotices(workNoticeJson);
        addWorkNotice(workNoticeJson);
    }


    /**
     * 开工
     * @param workNoticeJson 通知单数据
     */
    public void startWorkNotice(JSONObject workNoticeJson){
        checkNotice(workNoticeJson);
        workCenterService.updateById(getBeginJson(this.workCenter.getId(),this.workCenter.getClassName(),workCenterType,new JSONObject()));
        updateWorkCenterStatus(this.workCenter.getId(),BasicStatus.WORK_CENTER_STATUS_BEGIN);
        childInstanceService.updateById(getNoticeBeginJson(workNoticeJson.getLong("id"),this.workNoticeClassName,this.workNoticeType,JsonUtil.toJSONObject(JsonUtil.get(workNoticeJson,"values"))));
        updateWorkNoticeStatus(workNoticeJson.getLong("id"),BasicStatus.WORK_NOTICE_STATUS_BEGIN);
        this.workUnit.startWorkNotice(workNoticeJson);
    }

    /**
     * 完工
     * @param workNoticeJson 通知单数据
     */
    public void endWorkNotice(JSONObject workNoticeJson){
        checkNotice(workNoticeJson);
        workCenterService.updateById(getEndJson(this.workCenter.getId(),this.workCenter.getClassName(),workCenterType,new JSONObject()));
        updateWorkCenterStatus(this.workCenter.getId(),BasicStatus.WORK_CENTER_STATUS_FINISH);
        childInstanceService.updateById(getNoticeEndJson(workNoticeJson.getLong("id"),this.workNoticeClassName,this.workNoticeType,JsonUtil.toJSONObject(JsonUtil.get(workNoticeJson,"values"))));
        updateWorkNoticeStatus(workNoticeJson.getLong("id"),BasicStatus.WORK_NOTICE_STATUS_FINISH);
        this.workUnit.endWorkNotice(workNoticeJson);
    }

    /**
     * 删除工作中心
     */
    public void delete(){
        workCenterService.deleteByIds(Arrays.asList(workCenter.getId()));
    }

    /**
     *
     */

    /**
     * 添加生产通知单
     * @param workNoticeJson
     */
    public void addWorkNotice(JSONObject workNoticeJson){
        addChild(this.workCenterModel,this.workCenter.getClassName(),this.workCenter.getId(),getParentIdByName(workNoticeName),JsonUtil.buildJson(new Object[]{"linkId",workNoticeJson.getLong("id"),"hierValues",workNoticeJson.getJSONObject("values")}));
        this.workNotice = workNoticeJson;
        workUnit.addWorkNotices(workNoticeJson);
    }
    /**
     * 弃用
     * 执行生产通知单
     * @param workNoticeJson 生产通知单
     */
    public void executeWorkNotice(JSONObject workNoticeJson){
        checkNotice(workNoticeJson);
        childInstanceService.updateById(getNoticeExecuteJson(workNoticeJson.getLong("id"),this.workNoticeClassName,this.workNoticeType,JsonUtil.toJSONObject(JsonUtil.get(workNoticeJson,"values"))));
        workUnit.addWorkNotices(workNoticeJson);
    }

    /**
     * 校验工单队列在工单中是否存在
     * @param workNoticeJson 通知单数据
     */
    /*private void checkNotice(JSONObject workNoticeJson) {
        if(CollectionUtil.isEmpty(this.workNotice)){
            throw new BusinessException("工作中心工单队列为空");
        }
        List<Long> noticeIds = this.workNotice.stream().map(workNotice -> workNotice.getLong("id")).collect(Collectors.toList());
        if(!noticeIds.contains(workNoticeJson.getLong("id"))){
            throw new BusinessException("工作中心工单队列中不存在id为："+ workNoticeJson.getLong("id")+"的工单");
        }
    }*/

    private void checkNotice(JSONObject workNoticeJson) {
        if(CollectionUtil.isEmpty(this.workNotice)){
            throw new BusinessException("工作中心工单为空");
        }
        if(!JsonUtil.get(this.workNotice,"id").equals(JsonUtil.get(workNoticeJson,"id"))){
            throw new BusinessException("工作中心不存在id为："+ workNoticeJson.getLong("id")+"的工单");
        }
    }

    /**
     * 获取执行json
     * @param id 实例id
     * @param className 实例类名
     * @param type 类型
     * @param values 值
     * @return
     */
    private JSONObject getExecuteJson(Long id, String className,String type,JSONObject values){
//        values.putAll(JsonUtil.buildJson(new Object[]{"status","执行","startTime", DateUtil.now()}));
        values.putAll(JsonUtil.buildJson(new Object[]{"startTime", DateUtil.now()}));
        return JsonUtil.buildJson(new Object[]{"id",id,"className",className,"type",type,"values",values});
    }
    /**
     * 获取开工json
     * @param id 实例id
     * @param className 实例类名
     * @param type 类型
     * @param values 值
     * @return
     */
    private JSONObject getBeginJson(Long id, String className,String type,JSONObject values){
//        values.putAll(JsonUtil.buildJson(new Object[]{"status","开工","startTime", DateUtil.now()}));
        values.putAll(JsonUtil.buildJson(new Object[]{"startTime", DateUtil.now()}));
        return JsonUtil.buildJson(new Object[]{"id",id,"className",className,"type",type,"values",values});
    }

    /**
     * 获取通知单实例化json
     * @param className 实例类名
     * @param type 类型
     * @param values 值
     * @return
     */
    private JSONObject getNoticeJson(String className,String type,JSONObject values){
        JSONObject workCenterJson = workCenterUtil.getWorkCenterInsJsonObjectList(this.workCenter);
        values.putAll(JsonUtil.buildJson(new Object[]{"workName",JsonUtil.get(workCenterJson,"values.name"),"workCenterId",this.workCenter.getId(),"workUnitId",this.workUnit.getWorkUnit().getId(),"status","创建"}));
        return JsonUtil.buildJson(new Object[]{"className",className,"type",type,"values",values});
    }

    /**
     * 获取通知单执行json
     * @param id 实例id
     * @param className 实例类名
     * @param type 类型
     * @param values 值
     * @return
     */
    private JSONObject getNoticeExecuteJson(Long id, String className,String type,JSONObject values){
        values.putAll(JsonUtil.buildJson(new Object[]{"workCenterId",this.workCenter.getId(),"status","执行"}));
        return JsonUtil.buildJson(new Object[]{"id",id,"className",className,"type",type,"values",values});
    }

    /**
     * 获取通知单开工json
     * @param id 实例id
     * @param className 实例类名
     * @param type 类型
     * @param values 值
     * @return
     */
    private JSONObject getNoticeBeginJson(Long id, String className,String type,JSONObject values){
//        values.putAll(JsonUtil.buildJson(new Object[]{"workCenterId",this.workCenter.getId(),"status","开工","startTime", DateUtil.now()}));
        values.putAll(JsonUtil.buildJson(new Object[]{"workCenterId",this.workCenter.getId(),"startTime", DateUtil.now()}));
        return JsonUtil.buildJson(new Object[]{"id",id,"className",className,"type",type,"values",values});
    }

    /**
     * 获取完工json
     * @param id 实例id
     * @param className 实例类名
     * @param type 类型
     * @param values 值
     * @return
     */
    private JSONObject getEndJson(Long id, String className,String type,JSONObject values){
//        values.putAll(JsonUtil.buildJson(new Object[]{"status","结束","endTime", DateUtil.now()}));
        values.putAll(JsonUtil.buildJson(new Object[]{"endTime", DateUtil.now()}));
        return JsonUtil.buildJson(new Object[]{"id",id,"className",className,"type",type,"values",values});
    }

    /**
     * 获取通知单完工json
     * @param id 实例id
     * @param className 实例类名
     * @param type 类型
     * @param values 值
     * @return
     */
    private JSONObject getNoticeEndJson(Long id, String className,String type,JSONObject values){
//        values.putAll(JsonUtil.buildJson(new Object[]{"status","完工","endTime", DateUtil.now()}));
        values.putAll(JsonUtil.buildJson(new Object[]{"endTime", DateUtil.now()}));
        return JsonUtil.buildJson(new Object[]{"id",id,"className",className,"type",type,"values",values});
    }

    /**
     * 1.测试案例：一期还原，只有一个工位
     * 配置端配置routing，测试中设定方法，模拟生产通知单（routing 名称），Routing，WorkCenter都实例化好
     * routing：启动，当前WorkCenter启动
     * WorkCenter中创建新的类离散掉
     * 2.开工变更WorkCenter状态，时间等
     * 3.报工变更WorkCenter状态，时间等
     * 5，领料记录与Bom对比
     * 6.异常暂时可以不用考虑
     * 7.报完工，查看是否有下一Workcenter，如果有，则启动下一WorkCenter
     */

}
